<template>
  <div class="chat-threads">
    <!--好友会话列表-->
    <CustomScrollbar :style="{ height: showGroup ? 'calc(100% - 40% - 42px)' : 'calc(100% - 42px)' }">
      <ul v-if="filteredSessions">
        <li
          v-for="session in filteredSessions"
          :key="session.id"
          class="thread-item"
          :class="{ active: currentSession && currentSession.id === session.id }"
          @contextmenu.prevent="e => showContextMenu(session, e)"
          @click="onSessionClick(session)">
          <div style="position: relative; display: inline-block; margin-right: 10px">
            <img
              class="avatar"
              :src="$withContext(session.receiver.avatar) || require('@/assets/images/avatar.png')"
              alt="" />
            <i v-if="session.unreadCount" class="msg-tips">{{ session.unreadCount }}</i>
          </div>
          <div class="thread-session">
            <span class="friend-name-row">
              <span class="friend-name">{{ session.receiver.name }}</span>
              <span v-if="session.latestMessage" class="time">{{ friendlyTime(session.latestMessage.createdAt) }}</span>
            </span>
            <div v-if="session.latestMessage" class="new-msg">
              <p v-if="session.latestMessage.type === 'recall'">
                {{
                  session.latestMessage.recall?.userId === userId ? '你' : session.latestMessage.recall.name ?? '系统'
                }}撤回了一条{{
                  session.latestMessage.recall?.userId === session.latestMessage.sender.userId
                    ? ''
                    : session.latestMessage.sender?.userId === userId
                    ? '你的'
                    : `${session.latestMessage.sender.name}的`
                }}消息
              </p>
              <p v-else>{{ filterHtml(session.latestMessage) }}</p>
            </div>
          </div>
        </li>
      </ul>
    </CustomScrollbar>
    <!--  分组  -->
    <div class="group-tit" @click="showGroup = !showGroup">
      <i :class="showGroup ? 'el-icon-arrow-down' : 'el-icon-arrow-right'" class="folder-tool"></i>群组
    </div>
    <!--群聊会话列表-->
    <CustomScrollbar v-show="showGroup" class="group">
      <ol v-if="groupSessions">
        <li
          v-for="session in groupSessions"
          :key="`${session.id}F`"
          class="thread-item"
          :class="{ active: currentSession && currentSession.id === session.id }"
          @contextmenu.prevent="e => showContextMenu(session, e)"
          @click="onSessionClick(session)">
          <div style="position: relative; display: inline-block; margin-right: 10px">
            <img class="avatar" :src="require('@/assets/images/avatar.png')" alt="" />
            <i v-if="session.unreadCount" class="msg-tips">{{ session.unreadCount }}</i>
          </div>
          <div class="thread-session">
            <span class="friend-name-row">
              <span class="friend-name">{{ session.group.name }}</span>
              <span v-if="session.latestMessage" class="time">{{ friendlyTime(session.latestMessage.createdAt) }}</span>
            </span>
            <p v-if="session.latestMessage" class="new-msg" v-html="filterHtml(session.latestMessage)"></p>
          </div>
        </li>
      </ol>
    </CustomScrollbar>
    <!--  上下文菜单  -->
    <ContextMenu ref="contextMenu" :list="menu" @on-item-click="onMenuItemClick" />
  </div>
</template>

<script>
  import { filterHtml } from '@web-utils/core'
  import { friendlyTime, toDate } from '@web-utils/integrations/dayjs'
  import { mapMutations, mapState } from 'vuex'
  import message from '@/vue/mixin/message'
  import { getSessions, hideSession } from './api/session'
  import { makeRead } from './api/message'
  import { deleteGroup } from '@/components/im/api/group'

  export default {
    name: 'ChatThreads',
    mixins: [message],
    message: {
      chat(data) {
        const message = data.content.content
        this.updateLatestMessage(message)
      },
      newChat() {
        this.getSessions()
      },
      removeMember(data) {
        this.onMembersChanged(data)
      },
      addMember(data) {
        this.onMembersChanged(data)
      }
    },
    props: {
      query: {
        type: String,
        default: ''
      }
    },
    data() {
      return {
        showGroup: true,
        sessions: [],
        currentSession: {},
        contextSession: {}
      }
    },
    computed: {
      ...mapState('im', ['chatWindowVisible', 'activeThreadId']),
      ...mapState('user', { userId: state => state.sysUser.userId }),
      menu() {
        const menu = [
          {
            text: '移除聊天',
            action: 'hideSession',
            icon: 'el-icon-chat-line-square'
          }
        ]
        if (this.contextSession.group && this.contextSession.group.owner.userId === this.userId) {
          menu.push({
            text: '解散群聊',
            action: 'deleteGroup',
            icon: 'el-icon-circle-close'
          })
        }
        return menu
      },
      filteredSessions() {
        if (this.query) {
          return this.p2pSessions.filter(value => value.receiver.name.indexOf(this.query) > -1)
        }
        return this.p2pSessions
      },
      p2pSessions() {
        return this.sessions.filter(value => value.type === 'p2p')
      },
      groupSessions() {
        return this.sessions.filter(value => value.type === 'group')
      }
    },
    watch: {
      currentSession: {
        deep: true,
        handler(newVal) {
          // const newVal = this.currentSession
          if (newVal) {
            this.$set(newVal, 'name', newVal.type === 'group' ? newVal.group.name : newVal.receiver.name)
          }
          this.$emit('input', newVal || {})
        }
      },
      chatWindowVisible(newVal) {
        if (newVal) {
          this.readCurrentSession()
        }
      },
      activeThreadId: 'activeSession'
    },
    created() {
      this.getSessions()
    },
    methods: {
      ...mapMutations('im', ['adjustUnreadCount', 'setUnreadCount', 'setActiveThreadId']),
      friendlyTime,
      filterHtml(message) {
        if (message.type === 'image') {
          return '[图片]'
        }
        if (message.type === 'file') {
          return '[文件]'
        }
        return filterHtml(message?.content ?? '')
      },
      async getSessions() {
        const res = await getSessions()
        this.sort(res.data.data)
        this.sessions = res.data.data
        this.setUnreadCount(this.sessions.reduce((acc, cur) => acc + cur.unreadCount, 0))
        this.currentSession = this.sessions.find(value => value.id === this.currentSession?.id)
      },
      async getSessionByThreadId(threadId, tryFetch) {
        let session = this.sessions.find(value => value.thread.id === threadId)
        if (!session && tryFetch) {
          await this.getSessions()
          session = this.sessions.find(value => value.thread.id === threadId)
        }
        return session
      },
      async readCurrentSession(forceMakeRead) {
        const session = this.currentSession
        if (session) {
          if (session.unreadCount > 0) {
            this.adjustUnreadCount(-session.unreadCount)
            session.unreadCount = 0
            await makeRead(session.thread.id)
          } else {
            if (forceMakeRead) {
              await makeRead(session.thread.id)
            }
          }
        }
      },
      async activeSession() {
        if (this.activeThreadId) {
          const session = await this.getSessionByThreadId(this.activeThreadId, true)
          if (session) {
            this.currentSession = session
            this.setActiveThreadId(null)
          }
        }
      },
      onSessionClick(session) {
        this.currentSession = session
        if (session.unreadCount > 0) {
          this.adjustUnreadCount(-session.unreadCount)
          session.unreadCount = 0
        }
      },
      sort(sessions) {
        sessions.sort((first, second) => {
          if (first.latestMessage && second.latestMessage) {
            return toDate(second.latestMessage.createdAt).getTime() - toDate(first.latestMessage.createdAt).getTime()
          } else if (first.latestMessage?.createdAt && !second.latestMessage?.createdAt) {
            return -1
          } else if (!first.latestMessage?.createdAt && second.latestMessage?.createdAt) {
            return 1
          } else {
            return 0
          }
        })
      },
      async updateLatestMessage(message) {
        const session = await this.getSessionByThreadId(message.thread.id)
        if (session) {
          session.latestMessage = message
          this.sort(this.sessions)
          if (this.chatWindowVisible && session === this.currentSession) {
            await this.readCurrentSession(true)
          } else {
            session.unreadCount += 1
            this.adjustUnreadCount(1)
          }
        } else {
          await this.getSessions()
        }
      },
      showContextMenu(item, e) {
        this.contextSession = item
        this.$refs.contextMenu.show(e)
      },
      onMenuItemClick(item) {
        this[item.action]?.(this.contextSession)
        this.contextSession = {}
      },
      async hideSession(session) {
        await hideSession(session.id)
        this.sessions = this.sessions.filter(value => value.id !== session.id)
        this.currentSession = this.sessions[0] || {}
      },
      async deleteGroup(session) {
        await this.$confirm('解散群聊后群内的聊天记录都会被删除,您确定要解散该群聊吗？', { type: 'warning' })
        await deleteGroup(session.group.id)
        this.sessions = this.sessions.filter(value => value.id !== session.id)
        this.currentSession = this.sessions[0] || {}
      },
      async onMembersChanged(data) {
        const message = JSON.parse(JSON.parse(data.content).content)
        const session = this.sessions.find(value => value.type === 'group' && value.group.id === message.groupId)
        if (message.userIds.includes(this.userId)) {
          if (session) {
            session.status = 1
          }
          await this.getSessions()
          await this.readCurrentSession()
        }
      }
    }
  }
</script>

<style lang="scss">
  $gray-color: #808080;

  .chat-threads {
    /* 减去搜索区域高度 */
    height: calc(100% - 50px);

    .thread-item {
      @include flex-row;
      align-items: center;
      padding: 10px;
      border-bottom: 1px solid #e0e0e0;
      cursor: pointer;

      .avatar {
        width: 42px;
        height: 42px;
        background-color: grey;
        border-radius: 50%;
      }

      &:first-child {
        border-bottom: 1px solid #e0e0e0;
      }

      // &:last-child {
      //  border-bottom: none;
      // }
      &:hover {
        background-color: #fff7ed;
      }

      &.active {
        background-color: #fff7ed;
      }
    }

    .avatar,
    .friend-name {
      vertical-align: middle;
    }

    .avatar {
      border-radius: 2px;
    }

    .group-tit {
      height: 42px;
      padding: 12px 15px;
      font-size: 1.1em;
      background-color: #f6f8fa;
      border-top: 1px solid #e0e0e0;
      border-bottom: 1px solid #e0e0e0;
      cursor: pointer;

      .folder-tool {
        margin-right: 6px;
      }
    }

    .group {
      height: 40%;
    }

    .thread-session {
      @include flex-item;
      overflow: hidden;

      .friend-name-row {
        display: flex;
        align-items: center;
      }

      .friend-name {
        position: relative;
        display: inline-block;
        flex: 1 1 auto;
        margin-bottom: 6px;
        overflow: hidden;
        font-size: 1.1em;
        white-space: nowrap;
        text-overflow: ellipsis;
      }

      .office {
        display: inline-block;
        max-width: 100px;
        height: 20px;
        margin-left: 14px;
        padding: 0 6px;
        overflow: hidden;
        color: $gray-color;
        font-size: 12px;
        line-height: 18px;
        white-space: nowrap;
        text-overflow: ellipsis;
        vertical-align: middle;
        background: #fff;
        border: 1px solid var(--border-color);
        border-radius: 10px;
      }

      .time {
        @include flex-not-shrink;
        float: right;
        color: $gray-color;
        font-size: 12px;
        white-space: nowrap;
      }
    }

    .new-msg {
      min-height: 16px;
      color: $gray-color;
      font-size: 0.8em;
      white-space: nowrap;

      @include ellipsis(1);
    }

    .msg-tips {
      position: absolute;
      top: 0;
      right: -10px;
      z-index: 1;
      display: inline-block;
      box-sizing: content-box;
      height: 18px;
      padding: 0 6px;
      color: #fff;
      font-size: 12px;
      font-style: normal;
      line-height: 18px;
      white-space: nowrap;
      text-align: center;
      background: #f0001c;
      border: 1px solid #fff;
      border-radius: 10px;
    }
  }
</style>
